[No QA] Fix stale artifacts cache on iOS - #99185
Conversation
|
looks good, two minor questions 😄 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a3cb63934e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@MelvinBot review |
|
@jakubstec perhaps you can get a peer review from someone at SWM? Also I'm going OOO and don't have time to review this one this week. It seems reasonable, but frankly Ruby is pretty foreign to me |
ReviewThe approach is sound and the mechanism holds up. I traced the build-time half against RN's own 1. Confirm the wiring lands in the HybridApp PodfileThis module is only consumed by the HybridApp build, so nothing in this repo calls the new 2. Agree with the bot: include the package name in the stampThe stamp at L53-L54 and the written stamp at L266-L267 key only on version, while the prefetch cache and 3. On the two open questions from the earlier review
Other things I verified (all good)
I can't exercise the iOS |
|
@MelvinBot according to
I don’t think it makes sense to complicate our pipeline here. This implementation is tailored to our specific needs, and it’s highly unlikely that we’ll use it this way in the future. |
|
You're right — I checked, and the collision I described can't happen. Dropping the suggestion. The stamp lives at Only optional nit left, take it or leave it: the cache comment right below explicitly says "a version alone does not identify an artifact," which is what sent me down this path. A half-line on the stamp noting it's per-sandbox so the package name is fixed would stop the next reader (or bot) from filing the same comment. Zero pipeline complexity. The other two points from my review stand as-is — nothing blocking from me. |
|
Hi @roryabraham, I can't provide helpful review here as I'm not familiar with Ruby. Can you assign someone else please? thanks! |
|
Yeah, I think we don't have many ruby developers on board 😅 |
|
Also, I missed this before:
But I can confirm that wiring lands in the HybridApp Podfile |
roryabraham
left a comment
There was a problem hiding this comment.
LGTM 👍🏼
Only thought is it's not clear to me why you shelled out to a bash script rather than just staying in Ruby, but NAB
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
Explanation of Change
CocoaPods caches our prebuilt React Native artifacts by their source URL. That URL carries only the
plain react-native version, so a new patches version lands at the same path and CocoaPods keeps the
old extraction. It may not even re-read the podspec that downloads the tarballs. The app then
silently builds against a stale artifact.
Upstream RN has the same issue with Debug and Release artifacts (the cache does not distinguish
them either) and solves it outside CocoaPods. Its
[RNCore]build phase re-extracts the frameworkwhenever the
.last_build_configurationmarker does not match the current configuration. This PRextends that pattern to the patches version.
During
pod install, when the resolved version does not match the.artifacts-versionstamp ofthe tarballs in Pods, we drop CocoaPods' memoized podspec with
sandbox.remove_local_podspec. Thisforces a re-evaluation of the podspec, which re-runs podspec evaluation and the dSYM merge. The re-read
podspec is byte-identical, so
Podfile.lockis unaffected.During the build, a small prelude prepended into the
[RNCore]phase compares the tarballs' stampwith the extracted framework's stamp. On mismatch it writes
staleinto.last_build_configuration, and RN's own script re-extracts from the fresh tarballs right after.This reuses the upstream extraction machinery instead of duplicating it. It lives inside that phase
because CocoaPods sorts phases by name on save, so a separate phase could not run first.
The change covers patches version changes, the
RCT_SYMBOLICATE_PREBUILT_FRAMEWORKStoggle, warmsandboxes, removed Pods and interrupted builds. Debug and Release switching is untouched. When
nothing changed, both pieces are no-ops costing a couple of file reads.
Why this approach instead of a solution where we make CocoaPods differentiate between our patched versions? That would require significantly more effort and more patches to React Native internals. I’d prefer to keep our patched artifacts as close to upstream as possible to minimize the maintenance cost.
Fixed Issues
$ #99187
PROPOSAL:
MOBILE-EXPENSIFY: https://github.com/Expensify/Mobile-Expensify/pull/14066
Tests
Prerequisites: HybridApp iOS dev setup,
npm idone,gh auth login(Maven access), with successfulpod install+ build on this branch with the latest artifacts version (latestmainon both repos should be set).1. Note the current artifact version
cat Mobile-Expensify/ios/Pods/ReactNativeCore-artifacts/.artifacts-versionand note the version (e.g.0.86.0-5) — referred to as<current>below2. Force an older artifact version
scripts/artifacts-utils/lib/artifactsResolver.ts, add as the first line offindMatchingArtifactsVersion:3. Run pod install and verify it invalidates
cd Mobile-Expensify/ios && bundle exec pod install[PatchedArtifacts] Using patched react-native artifacts: react-hybrid:0.86.0-0[PatchedArtifacts] Artifacts changed to 0.86.0-0; the React-Core-prebuilt podspec will be re-evaluated.cat Pods/ReactNativeCore-artifacts/.artifacts-versionprints0.86.0-0git -C .. diff iOS/Podfile.lockshows no new changes4. Build and verify the extraction log
[PatchedArtifacts] Extracted prebuilt React Core is '<current>', tarballs are '0.86.0-0' — marking for re-extraction.Extracting the tarball to temp dir …cat Pods/React-Core-prebuilt/.patched-versionprints0.86.0-05. Verify the no-op fast path
marking for re-extractionline does NOT appear (silent = versions match)React-Core-prebuilt6. Revert and verify the round trip
artifactsResolver.tscd Mobile-Expensify/ios && bundle exec pod installand verify the output containsArtifacts changed to <current> …… is '0.86.0-0', tarballs are '<current>' — marking for re-extraction.followed by the extractioncat Pods/React-Core-prebuilt/.patched-versionis back to<current>Byte-level checks
dwarfdump --uuid Mobile-Expensify/ios/Pods/React-Core-prebuilt/React.xcframework/ios-arm64_x86_64-simulator/React.framework/Reactdwarfdump --uuid <DerivedData>/Build/Products/Debug-iphonesimulator/Expensify.app/Frameworks/React.framework/React0.86.0-0:6F445E91-…,0.86.0-5:7AFB6212-…)Offline tests
QA Steps
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari